package com.micro.ai.gateway.filter;

import com.micro.ai.commons.constant.ErrorCodeEnum;
import com.micro.ai.gateway.config.IpFilterProperties;
import com.micro.ai.gateway.util.IpUtils;
import com.micro.ai.gateway.util.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * IP黑白名单过滤器（优化版）
 * 实现IP访问控制，防止恶意IP访问
 * 支持IP过滤配置动态刷新
 * 
 * 优化点：
 * 1. 使用IpUtils统一IP获取逻辑
 * 2. 使用ResponseUtils统一错误响应
 * 3. 使用IpFilterProperties支持从Nacos动态刷新配置
 * 
 * @author micro-ai
 * @since 0.0.1
 * @version 1.3 支持动态刷新
 */
@Slf4j
@Component
public class IpFilter implements GlobalFilter, Ordered {

    @Autowired
    private ReactiveRedisTemplate<String, String> redisTemplate;

    @Autowired
    private IpFilterProperties ipFilterProperties;

    // Redis key
    private static final String IP_BLACKLIST_KEY = "gateway:ip:blacklist";
    private static final String IP_WHITELIST_KEY = "gateway:ip:whitelist";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 如果未启用IP过滤，直接放行
        if (!ipFilterProperties.isEnabled()) {
            return chain.filter(exchange);
        }

        ServerHttpRequest request = exchange.getRequest();
        String clientIp = IpUtils.getClientIp(request);

        log.debug("IP过滤器检查，客户端IP: {}", clientIp);

        // 1. 检查静态白名单（最高优先级，直接放行）
        if (isInStaticWhitelist(clientIp)) {
            log.debug("IP在静态白名单中，放行：{}", clientIp);
            return chain.filter(exchange);
        }

        // 2. 检查Redis白名单（如果启用）
        if (ipFilterProperties.isWhitelistEnabled()) {
            return checkWhitelist(clientIp)
                    .flatMap(isWhitelisted -> {
                        if (isWhitelisted) {
                            log.debug("IP在Redis白名单中，放行：{}", clientIp);
                            return chain.filter(exchange);
                        }
                        // 如果启用了白名单模式，不在白名单中的IP直接拒绝
                        log.warn("IP不在白名单中，拒绝访问：{}", clientIp);
                        return ResponseUtils.forbidden(exchange, ErrorCodeEnum.A0007.getCode(), "IP不在白名单中");
                    });
        }

        // 3. 检查黑名单（如果启用）
        if (ipFilterProperties.isBlacklistEnabled()) {
            return checkBlacklist(clientIp)
                    .flatMap(isBlacklisted -> {
                        if (isBlacklisted) {
                            log.warn("IP在黑名单中，拒绝访问：{}", clientIp);
                            return ResponseUtils.forbidden(exchange, ErrorCodeEnum.A0007.getCode(), "IP已被列入黑名单");
                        }
                        return chain.filter(exchange);
                    });
        }

        // 默认放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -880; // 在签名验证之前执行
    }

    /**
     * 检查是否在静态白名单中（支持动态刷新）
     */
    private boolean isInStaticWhitelist(String ip) {
        List<String> whitelist = ipFilterProperties.getStaticWhitelist();
        if (whitelist == null || whitelist.isEmpty()) {
            return false;
        }
        return whitelist.contains(ip);
    }

    /**
     * 检查Redis白名单
     */
    private Mono<Boolean> checkWhitelist(String ip) {
        return redisTemplate.opsForSet()
                .isMember(IP_WHITELIST_KEY, ip)
                .defaultIfEmpty(false)
                .onErrorReturn(false);
    }

    /**
     * 检查Redis黑名单
     */
    private Mono<Boolean> checkBlacklist(String ip) {
        return redisTemplate.opsForSet()
                .isMember(IP_BLACKLIST_KEY, ip)
                .defaultIfEmpty(false)
                .onErrorReturn(false);
    }

    /**
     * 添加IP到黑名单（提供给管理接口调用）
     */
    public Mono<Boolean> addToBlacklist(String ip) {
        return redisTemplate.opsForSet()
                .add(IP_BLACKLIST_KEY, ip)
                .map(count -> count > 0);
    }

    /**
     * 从黑名单移除IP
     */
    public Mono<Boolean> removeFromBlacklist(String ip) {
        return redisTemplate.opsForSet()
                .remove(IP_BLACKLIST_KEY, ip)
                .map(count -> count > 0);
    }

    /**
     * 添加IP到白名单
     */
    public Mono<Boolean> addToWhitelist(String ip) {
        return redisTemplate.opsForSet()
                .add(IP_WHITELIST_KEY, ip)
                .map(count -> count > 0);
    }

    /**
     * 从白名单移除IP
     */
    public Mono<Boolean> removeFromWhitelist(String ip) {
        return redisTemplate.opsForSet()
                .remove(IP_WHITELIST_KEY, ip)
                .map(count -> count > 0);
    }
}

